package main

// 引入所需的包
import (
	"encoding/json" // 用于解析和生成 JSON 数据
	"io"            // 用于基本的 I/O 操作
	"log"           // 用于记录日志
	"net/http"      // 用于处理 HTTP 请求和响应
	"os"            // 用于操作系统功能，如文件和命令执行
	"os/exec"       // 用于执行外部命令
)

// 定义 DeployRequest 结构体，用于接收 JSON 请求体中的数据
type DeployRequest struct {
	AppName     string `json:"appName"`     // 应用名称
	StaticImage string `json:"staticImage"` // 静态资源文件名
	InstallDir  string `json:"installDir"`  // 安装目录
}

// 定义处理部署请求的 HTTP 处理器函数
func staticDeployHandler(w http.ResponseWriter, r *http.Request) {
	// 检查请求方法是否为 POST
	if r.Method != http.MethodPost {
		log.Println("不支持的请求方法")
		http.Error(w, "不支持的请求方法", http.StatusMethodNotAllowed) // 如果不是 POST 请求，则返回 405 错误
		return
	}

	// 创建 JSON 解码器并解码请求体到 DeployRequest 结构体
	decoder := json.NewDecoder(r.Body)
	var req DeployRequest
	if err := decoder.Decode(&req); err != nil {
		log.Printf("解析JSON失败: %v", err)
		http.Error(w, "解析JSON失败: "+err.Error(), http.StatusBadRequest) // 如果 JSON 解析失败，则返回 400 错误
		return
	}

	// 记录收到的请求信息
	log.Printf("收到的请求: AppName=%s, StaticImage=%s, InstallDir=%s", req.AppName, req.StaticImage, req.InstallDir)

	// 构造 wget 下载命令的 URL 和命令
	wgetURL := "http://devops.wenwo.com:58080/software/?filename=upload/static/" + req.AppName + "/" + req.StaticImage
	wgetCommand := exec.Command("wget", wgetURL, "-O", req.InstallDir+"/"+req.StaticImage)
	log.Printf("执行下载: %s", wgetURL) // 记录下载操作
	// 执行 wget 命令并检查输出和错误
	if output, err := wgetCommand.CombinedOutput(); err != nil {
		log.Printf("下载文件失败: %s, 错误: %v", req.StaticImage, string(output))
		http.Error(w, "下载文件失败: "+string(output), http.StatusInternalServerError) // 如果下载失败，则返回 500 错误
		return
	}

	// 构造 unzip 解压命令并执行
	log.Printf("开始解压文件: %s", req.StaticImage)
	unzipCommand := exec.Command("unzip", "-o", req.InstallDir+"/"+req.StaticImage, "-d", req.InstallDir)
	if output, err := unzipCommand.CombinedOutput(); err != nil {
		log.Printf("解压文件失败: %s, 错误: %v", req.StaticImage, string(output))
		http.Error(w, "解压文件失败: "+string(output), http.StatusInternalServerError) // 如果解压失败，则返回 500 错误
		return
	}

	// 构造 rm 删除命令并执行
	log.Printf("删除ZIP文件: %s", req.StaticImage)
	rmCommand := exec.Command("rm", "-rf", req.InstallDir+"/"+req.StaticImage)
	if err := rmCommand.Run(); err != nil {
		log.Printf("删除ZIP文件失败: %v", err)
		http.Error(w, "删除ZIP文件失败: "+err.Error(), http.StatusInternalServerError) // 如果删除失败，则返回 500 错误
		return
	}

	// 记录部署成功信息
	log.Println("部署成功！")
	io.WriteString(w, "部署成功！") // 响应客户端部署成功的消息
}

// 主函数，程序入口点
func main() {
	// 指定日志文件的路径，并打开文件
	logPath := "/data/apps/staticdeploy/logs/deployment.log"
	logFile, err := os.OpenFile(logPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatalf("打开日志文件失败: %v", err) // 如果打开日志文件失败，则记录错误并退出程序
	}
	defer logFile.Close() // 确保在函数结束时关闭日志文件

	// 设置日志输出到指定的文件
	log.SetOutput(logFile)
	log.Println("服务启动，监听端口4824") // 记录服务启动信息

	// 设置 HTTP 路由，将 "/api/staticdeploy" 映射到 staticDeployHandler 函数
	http.HandleFunc("/api/staticdeploy", staticDeployHandler)
	// 启动 HTTP 服务器，监听 4824 端口，并处理传入的请求
	log.Fatal(http.ListenAndServe(":4824", nil)) // 如果启动失败，则记录错误并退出程序
}
